package com.xueyi.core.expection;


import com.xueyi.core.base.BaseResponse;
import com.xueyi.core.constants.SystemCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Objects;
import java.util.Set;

/**
 * ================================================================
 * 说明：全局异常处理
 * <p>
 * 作者          时间             注释
 * 鹿七        2018.7.26	      创建
 * ==================================================================
 */
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 解析异常信息
     *
     * @param t
     * @return
     */
    public static String getTrace(Throwable t) {
        StringWriter stringWriter = new StringWriter();
        PrintWriter writer = new PrintWriter(stringWriter);
        t.printStackTrace(writer);
        StringBuffer buffer = stringWriter.getBuffer();
        return buffer.toString();
    }

    /**
     * ----------------------------------------------------------------- 功能：处理全局异常
     * <p>
     * 返回：SystemResult
     * 异常结果信息
     * -------------------------------------------------------------------
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public BaseResponse<?> errorHandler(Exception e) {
        if (e instanceof HttpRequestMethodNotSupportedException) {
            return new BaseResponse<>(SystemCode.REQUEST_ERROR, "请求异常");
        }
        // 打印栈堆信息
        e.printStackTrace();
        log.error(getTrace(e));
        return new BaseResponse<>(SystemCode.ERROR, "程序内部异常,请稍后再试");
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public BaseResponse<?> methodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        // 打印栈堆信息
        e.printStackTrace();
        log.error("参数列表异常: {}", e.getMessage());
        return new BaseResponse<>(SystemCode.QUERY_CHECK_ERROR, "参数异常，即将返回列表");
    }

    /**
     * 处理数据校验异常
     *
     * @param exception 数据校验异常对象
     * @return
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public Object dataException(BindException exception) {
        // 返回数据校验错误信息
        return new BaseResponse<>(SystemCode.QUERY_CHECK_ERROR, Objects.requireNonNull(exception.getFieldError()).getDefaultMessage());
    }

    /**
     * spring 封装的参数验证异常， 在controller中没有写BindingResult参数时，会进入
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Object methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        return new BaseResponse<>(SystemCode.QUERY_CHECK_ERROR, Objects.requireNonNull(ex.getBindingResult().getFieldError()).getDefaultMessage());
    }


    /**
     * 处理请求单个参数不满足校验规则的异常信息
     *
     * @param exception 数据校验异常对象
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public Object constraintViolationExceptionHandler(ConstraintViolationException exception) {
        // 执行校验，获得校验结果
        Set<ConstraintViolation<?>> validResult = exception.getConstraintViolations();
        // 返回错误信息
        return new BaseResponse<>(SystemCode.QUERY_CHECK_ERROR, validResult.iterator().next().getMessage());
    }

    /**
     * -----------------------------------------------------------------
     * 功能：处理全局异常
     * <p>
     * 返回：SystemResult 异常结果信息
     * -------------------------------------------------------------------
     */
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public BaseResponse<?> illegalArgumentException(IllegalArgumentException e) {
        // 打印栈堆信息
        log.error(e.getMessage());
        return new BaseResponse<>(SystemCode.QUERY_CHECK_ERROR, e.getMessage());
    }

    /**
     * -----------------------------------------------------------------
     * 功能：处理全局异常
     * <p>
     * 返回：SystemResult 异常结果信息
     * -------------------------------------------------------------------
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public BaseResponse<?> szException(BusinessException e) {
        log.error(e.getMessage());

        // 打印栈堆信息
        return BaseResponse.build(e.code, e.getMessage());
    }
}
